package com.wsoft.bpm.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import com.wsoft.bpm.bean.ApprovalChainNode;
import com.wsoft.bpm.enums.ExecuteType;
import com.wsoft.bpm.query.mapping.ExtraBusinessDataQuery;
import com.wsoft.bpm.query.run.AgreeQuery;
import com.wsoft.bpm.service.RunProcessService;
import com.wsoft.bpm.service.WorkFlowService;
import com.wsoft.core.exception.Asserts;
import com.wsoft.core.utils.TableNameUtils;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author zhonglj
 * @Date 2025/1/9 13:30
 */
@Service
public class WorkFlowServiceImpl implements WorkFlowService {
    @Resource
    private RunProcessService runProcessService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private ChainWorkFlowService chainWorkFlowService;

    @Override
    public String startProcess(String processDefinitionKey, Class<?> entityClass, String businessKey, ExtraBusinessDataQuery extraData, Map map) {
        String tableName = TableNameUtils.getTableName(entityClass);
        return startProcess(processDefinitionKey, tableName, businessKey, extraData, map);
    }

    @Override
    public String startProcess(String processDefinitionKey, String tableName, String businessKey, ExtraBusinessDataQuery extraData, Map map) {
        return runProcessService.startProcess(processDefinitionKey, tableName, businessKey, extraData, map);
    }

    @Override
    public String startProcess(String processDefinitionKey, String tableName, String businessKeyColumn, String businessKey, String statusColumn, ExtraBusinessDataQuery extraData, Map map) {
        return runProcessService.startProcess(processDefinitionKey, tableName, businessKeyColumn, businessKey, statusColumn, extraData, map);
    }

    @Override
    public void agree(String taskId, String comment) {
        AgreeQuery query = new AgreeQuery();
        query.setTaskId(taskId);
        query.setComment(comment);
        query.setAuthCheck(true);
        runProcessService.agree(query);
    }

    @Override
    public void refuse(String taskId, String comment) {
        runProcessService.refuse(taskId, comment, true);
    }

    @Override
    public Object getVariable(String businessKey, String variableName) {
        ProcessInstance processInstance = getProcessInstance(businessKey);
        String rootExecutionId = processInstance.getId();
        return runtimeService.getVariable(rootExecutionId, variableName);
    }

    @Override
    public void setVariable(String businessKey, String variableName, Object value) {
        ProcessInstance processInstance = getProcessInstance(businessKey);
        String rootExecutionId = processInstance.getId();
        runtimeService.setVariable(rootExecutionId, variableName, value);
    }

    @Override
    public void setVariable(String businessKey, Map<String, Object> variables) {
        if (MapUtil.isNotEmpty(variables)) {
            ProcessInstance processInstance = getProcessInstance(businessKey);
            String rootExecutionId = processInstance.getId();
            runtimeService.setVariables(rootExecutionId, variables);
        }
    }

    @Override
    public List<String> convertToCandidateFormat(List<String> groups, ExecuteType type) {
        if (type == null || CollUtil.isEmpty(groups)) {
            return groups;
        }

        ArrayList<ExecuteType> candidateTypes = CollUtil.newArrayList(ExecuteType.CANDIDATE_ORG, ExecuteType.CANDIDATE_LEVEL, ExecuteType.CANDIDATE_ROLE, ExecuteType.CANDIDATE_POSITION);
        if (candidateTypes.contains(type)) {
            return ExecuteType.convertCandidateGroups(groups, type);
        }

        return groups;
    }

    @Override
    public boolean resetDynamicApprovalChain(String businessKey, String variableKey, ArrayList<ApprovalChainNode> newNodes) {
        return chainWorkFlowService.resetDynamicApprovalChain(businessKey, variableKey, newNodes);
    }

    /**
     * 获取流程实例
     *
     * @param businessKey
     * @return org.activiti.engine.runtime.ProcessInstance
     * @author zhonglj
     * @date 2025/1/14 14:24
     **/
    private ProcessInstance getProcessInstance(String businessKey) {
        List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .active()
                .list();
        if (CollUtil.isEmpty(processInstances)) {
            Asserts.fail("[bpm.process.error.empty.task]");
        }
        if (CollUtil.size(processInstances) > 1) {
            Asserts.fail("[bpm.process.error.multiple.task]");
        }

        return processInstances.get(0);
    }
}
